package nachos.threads;
import nachos.ag.BoatGrader;
import nachos.machine.*;


public class Boat
{
    static BoatGrader bg;
    static int oahuChildren = 0;
    static int oahuAdults = 0;
    static int peopleLeftBehind = 0;
    static int molokaiChildren = 0;
    static int boatCapacity = 2;
    static Lock boatLock = new Lock();
    static Condition2 oahu = new Condition2(boatLock);
    static Condition2 molokai = new Condition2(boatLock);
    static Condition2 childRideWait = new Condition2(boatLock);
    static boolean boatInOahu = true;

    public static void selfTest()
    {
	BoatGrader b = new BoatGrader();
	
	System.out.println("\n ***Testing Boats with only 2 children***");
	begin(2, 2, b);

//	System.out.println("\n ***Testing Boats with 2 children, 1 adult***");
//  	begin(1, 2, b);

//  	System.out.println("\n ***Testing Boats with 3 children, 3 adults***");
//  	begin(3, 3, b);
    }

    public static void begin( int adults, int children, BoatGrader b )
    {
	// Store the externally generated autograder in a class
	// variable to be accessible by children.
	bg = b;
        oahuChildren = children;
        oahuAdults = adults;
        peopleLeftBehind = children + adults;
	// Instantiate global variables here
	boolean state = Machine.interrupt().disable();
        ThreadedKernel.scheduler.setPriority(2); 
        Machine.interrupt().restore(state);
	// Create threads here. See section 3.4 of the Nachos for Java
	// Walkthrough linked from the projects page.
        for(int i = 0; i < children; i++){
            Runnable r = new Runnable() {
                public void run() {
                    ChildItinerary();
                }
            };
            KThread t = new KThread(r);
            t.setName("Child " + i);
            t.fork();
        }
        for(int i = 0; i < adults; i++){
            Runnable r = new Runnable() {
                public void run() {
                    AdultItinerary();
                }
            };
            KThread t = new KThread(r);
            t.setName("Adult " + i);
            t.fork();
        }



        Alarm a = new Alarm();
        a.waitUntil(15000);
        
    }

    static void AdultItinerary()
    {
        boatLock.acquire();

        while(!boatInOahu || oahuChildren > 1 || boatCapacity < 2){
            oahu.sleep();
            
        }
        boatCapacity-= 2;
        bg.AdultRowToMolokai();
        boatInOahu = false;
        peopleLeftBehind--;
        oahuAdults--;
        boatCapacity+=2;

        molokai.wakeAll();

        oahu.wakeAll();

        boatLock.release();
        
    }

    static void ChildItinerary()
    {
        boolean imInOahu = true;
        boatLock.acquire();
        while(peopleLeftBehind > 0){
           if(imInOahu){
               oahu.wakeAll();
               while(!boatInOahu || boatCapacity < 1 || (oahuChildren < 2 && oahuAdults > 0)){
                   oahu.sleep();
               }
               
               oahu.wakeAll();
               boatCapacity--;
               if(boatCapacity == 0){
                   bg.ChildRideToMolokai();
                   peopleLeftBehind -=2;
                   oahuChildren -= 2;
                   molokaiChildren += 2;
                   imInOahu = false;
                   boatInOahu = false;
                   childRideWait.wakeAll();
                   
               }else{
                   bg.ChildRowToMolokai();
                   if(oahuChildren > 1){
                       oahu.wakeAll();
                       imInOahu = false;
                       childRideWait.sleep();
                   }
                   else{
                       peopleLeftBehind--;
                       oahuChildren--;
                       molokaiChildren++;
                       imInOahu = false;
                       boatInOahu = false;
                   }
               }
               boatCapacity++;
               molokai.wakeAll();

           }else {
              while(boatInOahu || boatCapacity < 2){
                   molokai.sleep();
              }
              
              boatCapacity--;
              bg.ChildRowToOahu();
              oahuChildren++;
              peopleLeftBehind++;
              imInOahu = true;
              boatInOahu = true;
              boatCapacity++;
              oahu.wakeAll();
           }           
        }
        
        boatLock.release();
    }

    static void SampleItinerary()
    {
	// Please note that this isn't a valid solution (you can't fit
	// all of them on the boat). Please also note that you may not
	// have a single thread calculate a solution and then just play
	// it back at the autograder -- you will be caught.
	System.out.println("\n ***Everyone piles on the boat and goes to Molokai***");
	bg.AdultRowToMolokai();
	bg.ChildRideToMolokai();
	bg.AdultRideToMolokai();
	bg.ChildRideToMolokai();
    }
    
}
